#ifndef __MY_DATA__
#define __MY_DATA__
#include "config.hpp"
#include <unordered_map>
namespace cloud {
    typedef struct BackupInfo{
        int pack_flag;
        time_t mtime;
        time_t atime;
        size_t fsize;
        std::string realpath;
        std::string url;
        std::string packpath;
        bool NewBackupInfo(const std::string &realpath) {
            cloud::FileUtil fu(realpath);
            if(fu.Exists() == false) {
                std::cout << "NewBackupInfo:file not exists.\n";
                return false;
            }
            cloud::Config *config = cloud::Config::GetInstance();
            std::string packdir = config->GetPackDir();
            std::string suffix = config->GetPackfileSuffix();
            std::string prefix = config->GetDownloadPrefix();
            this->pack_flag = false;
            this->mtime = fu.LastMTime();
            this->atime = fu.LastATime();
            this->fsize = fu.FileSize();
            this->realpath = realpath;
            this->packpath = packdir + fu.FileName() + suffix;
            this->url = prefix + fu.FileName();
            return true;
        }
    }BackupInfo;
    class DataManager{
        private:
            std::string _backup_file;
            pthread_rwlock_t _rwlock;
            std::unordered_map<std::string, BackupInfo> _table;
        public:
            DataManager() {
                _backup_file = cloud::Config::GetInstance()->GetBackupFile();
                pthread_rwlock_init(&_rwlock, NULL);
                InitLoad();
            }
            ~DataManager() {
                pthread_rwlock_destroy(&_rwlock);
            }
            bool InitLoad()//初始化程序运行时从文件读取数据
            {
                FileUtil fu(_backup_file);
                if(fu.Exists() == false) 
                {
                    std::cout << "backup_file not exists\n";
                    return false;
                }
                std::string body;
                fu.GetContent(&body);
                Json::Value root;
                JsonUtil::UnSerialize(body, &root);
                for(int i = 0; i < root.size(); i++)
                {
                    BackupInfo info;
                    info.pack_flag = root[i]["pack_flag"].asBool();
                    info.atime = root[i]["atime"].asInt64();
                    info.mtime = root[i]["mtime"].asInt64();
                    info.fsize = root[i]["fsize"].asInt64();
                    info.packpath = root[i]["packpath"].asString();
                    info.realpath = root[i]["realpath"].asString();
                    info.url = root[i]["url"].asString();
                    this->Insert(info);
                }
                return true;
            }
            bool Storage() //每次有信息改变则需要持久化存储一次
            {
                //获取数据
                std::vector<BackupInfo> arry;
                this->GetAll(&arry);
                //添加到json::value
                Json::Value root;
                for(int i = 0; i < arry.size(); ++i)
                {
                    Json::Value item;
                    item["pack_flag"] = arry[i].pack_flag;
                    item["fsize"] = (Json::Int64)arry[i].fsize;
                    item["atime"] = (Json::Int64)arry[i].atime;
                    item["mtime"] = (Json::Int64)arry[i].mtime;
                    item["url"] = arry[i].url;
                    item["packpath"] = arry[i].packpath;
                    item["realpath"] = arry[i].realpath;
                    root.append(item); 
                }
                //对json::value序列化
                std::string body;
                JsonUtil::Serialize(root, &body);
                //写文件
                FileUtil fu(_backup_file);
                return fu.SetContent(&body);     
            }
            bool Insert(const BackupInfo &info)
            {
                pthread_rwlock_wrlock(&_rwlock);
                _table[info.url] = info;
                pthread_rwlock_unlock(&_rwlock);
                Storage();
                return true;
            }
            bool Update(const BackupInfo &info)
            {
                pthread_rwlock_wrlock(&_rwlock);
                _table[info.url] = info;
                pthread_rwlock_unlock(&_rwlock);
                Storage();

                return true;
            }
            bool GetOneByURL(const std::string &url, BackupInfo *info)
            {
                pthread_rwlock_wrlock(&_rwlock);
                auto it = _table.find(url);
                if(it == _table.end()) 
                {
                    pthread_rwlock_unlock(&_rwlock);
                    return false;
                }
                *info = it->second;
                pthread_rwlock_unlock(&_rwlock);
                return true;
            }
            bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)
            {
                pthread_rwlock_wrlock(&_rwlock);
                for(auto it = _table.begin(); it != _table.end(); it++)
                {
                    if(it->second.realpath == realpath)
                    {
                        *info = it->second;
                        pthread_rwlock_unlock(&_rwlock);
                        return true;
                    }   
                }
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            bool GetAll(std::vector<BackupInfo> *arry)
            {
                pthread_rwlock_wrlock(&_rwlock);
                for(auto it = _table.begin(); it != _table.end(); it++)
                {
                    arry->push_back(it->second);  
                }
                pthread_rwlock_unlock(&_rwlock);
                return true;
            }
       };

}

   #endif